/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package agents;

import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.ParallelBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.ArtMuseum;
import model.Artifact;
import view.CuratorGUI;

/**
 *
 * @author CUNEYT
 *
 * This class is the Curator Agent which is responsible for monitoring a museum and responding to
 * the requests made by the Tour Guide agents and Profiler agents.
 *
 *
 */
public class CuratorAgent extends Agent {

    private ArtMuseum catalogue;
    private CuratorGUI gui;

    @Override
    protected void setup() {
        catalogue = new ArtMuseum();
        gui = new CuratorGUI(this);
        gui.setVisible(true);

        registerService();
        /*
         * This agent has two behaviours/services running concurrently. Thus, a parallel behaviour with
         * these services is added to support this property.
         */
        ParallelBehaviour pb = new ParallelBehaviour(this, ParallelBehaviour.WHEN_ALL);
        pb.addSubBehaviour(new RequestServer());
        pb.addSubBehaviour(new DetailServer());
        addBehaviour(pb);
    }

    /*
     * This method is invoked at the initialization of the agent in order to register
     * the services provided by this agent to the Directory Facilitator.
     */

    private void registerService() {
        DFAgentDescription dfad = new DFAgentDescription();
        dfad.setName(getAID());
        ServiceDescription sd = new ServiceDescription();
        sd.setType("museum/gallery");
        sd.setName("DAIIA10-HW1-CURATOR");
        dfad.addServices(sd);
        try {
            DFService.register(this, dfad);
        } catch (FIPAException ex) {
            Logger.getLogger(CuratorAgent.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    protected void takeDown() {
        gui.dispose();
        try {
            DFService.deregister(this);
        } catch (FIPAException ex) {
            Logger.getLogger(CuratorAgent.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


    /*
     * This method is invoked by the GUI in order to add an Artifact to the museum catalogue.
     */
    public void addArtifact(final String id, final String name, final String category, final String creator, final String date, final String place, final String genre) {
        catalogue.addArtifact(new Artifact(id, name, creator, date, place, genre, category));
    }

    /*
     * This private class is responsible for serving to the Profiler agent which requests a detailed information about
     * a specific artifact returned in a list by the tour guide. The expected parameter in the message is the id of the Artifact.
     * The class extends CyclicBehaviour which means that it will be available and running all the time unless it is explicitly stopped.
     */

    private class DetailServer extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.REQUEST);
            ACLMessage msg = myAgent.receive(mt);

            if (msg != null) {
                ACLMessage reply = msg.createReply();
                String parameter = msg.getContent();
                reply.setPerformative(ACLMessage.INFORM);
                try {
                    reply.setContentObject(catalogue.get(parameter));
                } catch (IOException ex) {
                    Logger.getLogger(CuratorAgent.class.getName()).log(Level.SEVERE, null, ex);
                }
                myAgent.send(reply);
            } else {
                block();
            }
        }
    }

    /*
     * This private class is responsible for serving the requests made by the tour guides to perform a lookup with
     * the specified search criterias and parameters. The class extends CyclicBehaviour which means that it will
     * be available and running all the time until it is stopped explicitly.
     */
    private class RequestServer extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP);
            ACLMessage msg = myAgent.receive(mt);

            if (msg != null) {
                ACLMessage reply = msg.createReply();
                String[] query = msg.getContent().split(",");
                // Checking for the message content whether the parameters are as they are expected.
                if (query.length != 2) {
                    reply.setPerformative(ACLMessage.REFUSE);
                    reply.setContent("Expected 2 arguments separated by comma(criteria, any parameter)");
                } else {
                    String searchBy = query[0].trim();
                    String criteria = query[1].trim();
                    ArrayList<String> result;
                    if (searchBy.equals(Artifact.CATEGORY)) {
                        result = catalogue.getArtifactsByCategory(criteria);
                    } else if (searchBy.equals(Artifact.NAME)) {
                        result = catalogue.getArtifactsByName(criteria);
                    } else if (searchBy.equals(Artifact.CREATOR)) {
                        result = catalogue.getArtifactsByCreator(criteria);
                    } else if (searchBy.equals(Artifact.GENRE)) {
                        result = catalogue.getArtifactsByGenre(criteria);
                    } else {
                        result = null;
                    }

                    if (result == null) {
                        reply.setPerformative(ACLMessage.REFUSE);
                        reply.setContent("criteria not available");
                    } else {
                        reply.setPerformative(ACLMessage.PROPOSE);
                    }
                    try {
                        reply.setContentObject(result);
                    } catch (IOException ex) {
                        Logger.getLogger(CuratorAgent.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                reply.setReplyWith(msg.getReplyWith());
                myAgent.send(reply);
            } else {
                block();
            }
        }
    }
}
